#Custom Imports
from .types import *

any_type = AnyType("*") #Types.AnyType("*")
MAX_SLOTS = 10 #Adjust this value to change how many inputs/outputs the dynamic nodes in this pack expose.
reverse = slice(None,None,-1)

class UniversalSwitch:

	#TODO: Make input and output amounts dynamic and have a working setting for type validation.
	max_slots = MAX_SLOTS
	default_to_first = True #Constant which determines whether to output on the first slot even if no valid connections are found.

	@classmethod
	def INPUT_TYPES(s):

		dynamic_inputs = {"input2": (any_type, {"lazy": True}),}
		for x in range(2, s.max_slots+1):
			dynamic_inputs[f"input{x}"] = (any_type, {"lazy": True,"tooltip":"Data to forward through the Universal Switch"})
		return {
			"required": { "input1": (any_type, {"lazy": True,"tooltip": "Data to forward through the Universal Switch"}),
			"mode": (["SWITCH","PASSTHROUGH","CYCLE","SORT","REVERSE"],{"tooltip": "Mode that will be used to select Inputs and Outputs"}),
			"selection_in": ("INT", {"default": 1, "min": -1, "max": s.max_slots, "step": 1, "defaultInput": False, "tooltip":"Which Input slot to select from (0=Auto,-1=All)"}),
			"selection_out": ("INT", {"default": 1, "min": -1, "max": s.max_slots, "step": 1, "defaultInput": False, "tooltip":"Which Output slot to transmit to (0=Auto,-1=All)"}),
			"validate_typing": ("BOOLEAN", {"defaultInput": False,"tooltip":"[UNIMPLEMENTED] Match Input types to their relative Outputs"}),
			}, "optional": dynamic_inputs, "hidden": {"prompt": "PROMPT", "unique_id": "UNIQUE_ID",}, #"extra_pnginfo": "EXTRA_PNGINFO"},
		}

	RETURN_TYPES =	tuple([any_type for x in range(1,max_slots+1)])
	RETURN_NAMES = tuple(list("*" * max_slots))
	OUTPUT_TOOLTIPS = tuple(["Output "+ str(x) for x in range(1,max_slots+1)],)
	FUNCTION = "switch"
	CATEGORY = "Genera"
	DESCRIPTION = \
"""Allows you to pick a specific Input or Output to control the flow of execution
and transmit data variably based on your selections.

Selection_In determines what Input slot will be transmitted and Selection_Out
specifies what slot that data will be output to. All other Outputs from this
node that are not used will return None. This node supports Lazy evaluation.
Only the Inputs that are required based on the selections will be executed.

Depending on the mode this node is set to, different actions will occur:
• SWITCH: Transmits the Input chosen by Selection_In on the Output of Selection_Out.
• CYCLE: Similar to SWITCH but all subsequent Outputs will be matched linearly
after the chosen Input, wrapping around until all Inputs are matched.
• PASSTHROUGH: All Inputs will be directly matched to all Outputs.
(Selection_in and Selection_Out are ignored).
• SORT: All Inputs will be sorted and matched to all Outputs.
(Selection_in and Selection_Out are ignored).
• REVERSE: All Inputs will be inversely matched to all Outputs.
(Selection_in and Selection_Out are ignored).

If Selection_In is set to 0 (for Modes that support it), the first Input that isn't
None will be selected. Similarly, Selection_Out will pick the first Output slot
that has a valid connection.

With Selection_In set to -1, all Inputs will be packed into a List and output
through the slot specified by Selection_Out. With Selection_Out set to -1,
the Input chosen by Selection_In will be sent to ALL Outputs simultaneously.
A Selection_In of -1 and a Selection_Out of -1 will match ALL Input Nodes and
ALL Output nodes respectively. With both values set to -1, this is equivalent
to PASSTHROUGH mode.

If Validate_Typing is enabled, Outputs will match the type of their respective Inputs. (Currently this functionality is unimplemented).

HOVER OVER THE INPUTS AND OUTPUTS FOR MORE INFO.
"""
	def check_lazy_status(s, *args, **kwargs):

		selection = int(kwargs['selection_in'])

		inputs = []

		if selection > 0 and kwargs['mode'] == "SWITCH":
			inputs = [f"input{selection}"]
		else:
			print ("SWITCH [",kwargs['unique_id'],"] UNABLE TO LAZY CHECK, REQUESTING ALL INPUTS.")
			for x in range(1,s.max_slots+1):
				inputs.append("input"+str(x))

		print ("SWITCH [",kwargs['unique_id'],"] LAZY CHECK REQUESTED: ", inputs)

		return inputs

	def switch(s,input1,mode,selection_in,selection_out,validate_typing,**kwargs):

		def find_valid_output(kwargs):

			unique_id,prompt = kwargs.pop('unique_id'),kwargs.pop('prompt') #workflow_info = kwargs.pop('extra_pnginfo')
			val_out = None

			print ("\n>> SWITCH [",unique_id,"]: MODE =",mode)
			#print ("\nPROMPT:\n",prompt,"\n") #,"\n\nEXTRA INFO:\n",workflow_info)

			for x in range(0,s.max_slots):
				if	"'source': ['"+str(unique_id)+"', " + str(x) + "]" in str(prompt):
					val_out = x+1; break

			print (">> FIRST VALID OUTPUT SLOT:",val_out)
			return val_out

		selected_slot = None
		valid_out = find_valid_output(kwargs)
		if selection_out == 0: selection_out = valid_out

		options = [input1]
		for key,value in kwargs.items(): options.append(value)

		print (">> OPTIONS:",options)

		if selection_in == 0:
			i=0
			for input in options:
				i+=1
				if input is not None:
					selected_slot = input; selection_in = i
					print (">> SELECTED INPUT SLOT (FIRST VALID):",i)
					break

		elif selection_in > 0:
			if selection_in >= len(options):
				selected_slot = options[len(options)-1]
			else:
				selected_slot = options[selection_in-1]

		elif selection_in == -1:

			if selection_out == -1:
				mode = "PASSTHROUGH"
			else:
				selected_slot = options

		print (">> SELECTED SLOTS -> INPUT:",selection_in," OUTPUT:",selection_out)

		match mode:

			case "SWITCH":

				if selection_out is None:
					print (">> NO OUTPUTS CONNECTED!")
					ret = [None] * (s.max_slots)

					if (s.default_to_first):
						print (">> DEFAULTING TO FIRST OUTPUT SLOT!")
						ret[0] = selected_slot

				elif selection_out == -1:
					ret = [selected_slot for x in range(0,s.max_slots)]

				else:
					ret = [None] * (s.max_slots)
					ret[selection_out-1] = selected_slot

			case "CYCLE":

				ret = [None] * (s.max_slots)

				for x in range(0,s.max_slots):

					i = x+selection_in-1
					print ("I=",i)
					if i > s.max_slots-1:
						i-=s.max_slots
						print ("new I=",i)

					j = x+selection_out-1
					print ("J=",j)
					if j > s.max_slots-1:
						j-=s.max_slots
						print ("new J=",j)

					ret[j] = options[i]

			case "PASSTHROUGH":

				ret = options

			case "SORT":

				ret = sorted(options)

			case "REVERSE":

				ret = options[reverse]

		#print("\n>> RETURN: ", ret)

		return tuple(ret)

	@classmethod
	def IS_CHANGED(s,**kwargs):
		return float("nan")